﻿package classes 
{
	import classes.*;
	
	import commands.*;
	import commands.classesinfo.*;
	
	import flash.utils.ByteArray;
	import flash.xml.XMLDocument;
	import flash.xml.XMLNode;
	
	//import mx.controls.Alert;
	//import mx.core.FlexGlobals;
	
	/**
	 * ...
	 * @author wwx
	 */
	public class CommandTransfer 
	{
		
		private var _tcpSocket:TCPSocket = null;;
		
		private var _protocolTranslater:ProtocolTranslater = null;
		
		private var _callbackFun:Function = null;
		
		private var _RoomsManager:RoomsManager = null;
		
		private var _userInfo:UserInfo = null;
		
		private var _gameId:int = -1;
		
		private var _enterRoomCmdReq:EnterRoomCmdReq = null;
		
		public function CommandTransfer(callback:Function,xml:String) 
		{
			_tcpSocket = null;
			_protocolTranslater = new ProtocolTranslater();
			_callbackFun = callback;
			_RoomsManager = new RoomsManager(_protocolTranslater,_callbackFun);
			
			BytesValueConverter.just();
			
			var dsis:Array = null;
			dsis = loadXML(xml);
			_RoomsManager.setDirectoryServerInfo(dsis,_gameId);
		}
		
		private function loadXML(str:String):Array
		{
			var directoryServerInfos:Array = new Array();
			var dsi:DirectoryServerInfo = null; 
			var xml:XMLDocument = new XMLDocument();
			xml.ignoreWhite = true;
			xml.parseXML(str);
			
			/*
			<UserInfo id="" name="" password="">				
			</UserInfo>
			<GameInfo id="">
			</GameInfo>
			<DServers>
				<DServer ip="127.0.0.1" port="554" />
			</DServers>;
			 */
			var nodes:Array = xml.childNodes;
			trace("CommandTransfer load xml");
			for each(var node:XMLNode in nodes)
			{
				switch(node.nodeName)
				{
					case "UserInfo":
					{
						_userInfo = new UserInfo();
						_userInfo.userId = int(node.attributes.id);
						_userInfo.username = node.attributes.name;
						_userInfo.password = node.attributes.password;
					}
						break;
					case "GameInfo":
					{
						_gameId = int(node.attributes.id);
					}
						break;
					case "DServers":
					{
						for each(var server:XMLNode in node.childNodes)
						{
							dsi = new DirectoryServerInfo();
							dsi.g_strIp = server.attributes.ip;				
							dsi.g_iPort = int(server.attributes.port);
							directoryServerInfos.push(dsi);
							trace("ip="+dsi.g_strIp+",port="+dsi.g_iPort);
						}
					}
						break;
					default:
						break;
				}

			}
			
			return directoryServerInfos;
		}
		
		public function getGameID():int
		{
			return _gameId;
		}
		
		private function connectToServer(strIP:String,port:int):int
		{
			if (null != _tcpSocket)
			{
				_tcpSocket.close();
			}
			_tcpSocket = new TCPSocket(strIP, port, recvEventCallback);
			return _tcpSocket.connect();
		}
		
	
		//private var m_header:ByteArray = new ByteArray();
		private var m_cmdBuffer:ByteArray = new ByteArray();
		private function recvDataCallback():void
		{
			var cmdLen:int = 0;
			var recvLen:int = 0;
			var bytesInSocket:int = _tcpSocket.getBytesAvailable();
			//trace("bytesInSocket=" + bytesInSocket);
			while (0 < bytesInSocket)
			{
				if (m_cmdBuffer.position < 4)
				{
					recvLen = _tcpSocket.recv(m_cmdBuffer, m_cmdBuffer.position, 4 - m_cmdBuffer.position);
					if (0 < recvLen)
					{
						m_cmdBuffer.position += recvLen;
						bytesInSocket -= recvLen;
					}
					else
					{
						trace("recv error");
						return;
					}
				}
				//trace("m_cmdBuffer.position=" + m_cmdBuffer.position);
				if (4 > m_cmdBuffer.position)
					return;
				
				cmdLen = m_cmdBuffer[0] + ((int(m_cmdBuffer[1])) << 8) + ((int(m_cmdBuffer[2])) << 16) + ((int(m_cmdBuffer[3])) << 24);			
				cmdLen -= m_cmdBuffer.position;
				recvLen = _tcpSocket.recv(m_cmdBuffer, m_cmdBuffer.position, cmdLen);
				if (0 < recvLen)
				{
					m_cmdBuffer.position += recvLen;
					bytesInSocket -= recvLen;
				}
				//trace("m_cmdBuffer.position=" + m_cmdBuffer.position + ",cmdLen=" + cmdLen);
				if (cmdLen + 4 != m_cmdBuffer.position)
				{
					return ;
				}
				
				//trace("recv cmd! " + recvLen);
				
				var cmdType:int = 0;
				var cmd:abCommand = null;
				cmdType = m_cmdBuffer[4] + ((int(m_cmdBuffer[5])) << 8) + ((int(m_cmdBuffer[6])) << 16) + ((int(m_cmdBuffer[7])) << 24);
				var ct:CommandType = CommandType.CMD_TYPE_UNKOWN;
				//FlexGlobals.topLevelApplication.traceLog("\n消息号："+cmdType);
				switch(cmdType)
				{
					case 30000000:
					ct = CommandType.CMD_TYPE_CREATEROLE_RSP;
					break;
					case 30000001:
					ct = CommandType.CMD_TYPE_LOGIN_RSP;
					break;
					case 30000002:
					ct = CommandType.CMD_TYPE_LOGOUT_RSP;
					break;
					case 30000003:
					ct = CommandType.CMD_TYPE_ENTERROOM_RSP;
					break;
					case 30000004:
					ct = CommandType.CMD_TYPE_EXITROOM_RSP;
					break;
					case 30000005:
					ct = CommandType.CMD_TYPE_SWITCHROOM_RSP;
					break;
					case 30000006:
					ct = CommandType.CMD_TYPE_ENTERDESK_RSP;
					break;
					case 30000007:
					ct = CommandType.CMD_TYPE_EXITDESK_RSP;
					break;
					case 30000008:
					ct = CommandType.CMD_TYPE_STARTPLAY_RSP;
					break;
					case 30000009:
					ct = CommandType.CMD_TYPE_INJECT_RSP;
					break;
					case 30000010:
					ct = CommandType.CMD_TYPE_ADDCHIP_RSP;
					break;
					case 30000011:
					ct = CommandType.CMD_TYPE_ADDCHIP_RSP;
					break;
					case 30000012:
					ct = CommandType.CMD_TYPE_GIVEUPPLAY_RSP;
					break;
					case 30000013:
					ct = CommandType.CMD_TYPE_FOLLOW_RSP;
					break;
					case 30000014:
					ct = CommandType.CMD_TYPE_PASS_RSP;
					break;
					case 30000015:
					ct = CommandType.CMD_TYPE_BRINGCHIPS_RSP;
					break;
					case 30000100:
					ct = CommandType.CMD_TYPE_RECHARGE_RSP;
					break;
					case 30000101:
					break;
					case 50000001:
					ct = CommandType.CMD_TYPE_DESKINOFUPDATE;
					break;
					case 50000002:
					ct = CommandType.CMD_TYPE_ASSIGNGOUNDCARD;
					break;
					case 50000003:
					ct = CommandType.CMD_TYPE_ASSIGNPUBLICCARD;
					break;
					case 50000004:
					ct = CommandType.CMD_TYPE_SENDTURNNINGCARD;
					break;
					case 50000005:
					ct = CommandType.CMD_TYPE_SENDRIVERCARD;
					break;
					case 50000006:
					ct = CommandType.CMD_TYPE_NOTIFYTOCHOOSEOPERATE;
					break;
					case 50000007:
					ct = CommandType.CMD_TYPE_SHOWDOWN;
					break;
					case 50000008:
					ct = CommandType.CMD_TYPE_RESULTOFGAME;
					break;
					case 50000009:
					ct = CommandType.CMD_TYPE_PLAYERLIST;
					break;
					case 50000010:
					ct = CommandType.CMD_TYPE_GAMESTARTNOTIFY;
					break;
					case 50000011:
					ct = CommandType.CMD_TYPE_POOLINFO;
					break;
					case 50000012:
					ct = CommandType.CMD_TYPE_BLINDPOSITION;
					break;
					default:
					break;
				}
				if (CommandType.CMD_TYPE_UNKOWN == ct)
				{
					trace("unkown type of command!type = " + cmdType);
					m_cmdBuffer.position = 0;
					return ;
				}			
				cmd = _protocolTranslater.convertToCmd(ct, m_cmdBuffer, 4, recvLen);
				m_cmdBuffer.position = 0;
				if (null == cmd)
					return ;
					
				if (CommandType.CMD_TYPE_LOGIN_RSP == cmd.getCmdType())
				{
					//登录命令的返回。
					recvLoginRspFromGateServer(cmd as LoginCmdRsp);
				}
				else
				{
					_callbackFun(cmd);
				}
				m_cmdBuffer.position = 0;
			}
		}
		
		//连接到网关服务器的结果返回处理。
		private function connectedResult(status:int):void
		{
			//var cmd:ConnectStatusRsp = new ConnectStatusRsp();
			//cmd.status = status;			
			//_callbackFun(cmd);
			if (0 != status)
			{
				//连接不成功，返回进入房间出错信息。
				returnEnterRoomError( -1);
				return;
			}

			//连接成功，发登录命令。
			var loginCmd:LoginCmdReq = new LoginCmdReq();
			loginCmd.reserve = 0;
			loginCmd.userName = _userInfo.username;
			loginCmd.passWord = _userInfo.password;
			loginCmd.roleId = _userInfo.userId;
			if (0 != sendCmdToServer(loginCmd))
			{
				returnEnterRoomError( -1);
			}
		}
		
		//接收到网关服务器的登录返回命令。
		private function recvLoginRspFromGateServer(loginRsp:LoginCmdRsp):void
		{
			if (0 != loginRsp.errorNum)
			{
				returnEnterRoomError( -2);
				return;
			}
			
			//发进入房间命令。
			sendEnterRoomCmd();
		}
		
		//返回进入房间命令出错，回调到使用者。
		private function returnEnterRoomError(errorNum:int):void
		{
			var enterRoomRsp:EnterRoomCmdRsp = new EnterRoomCmdRsp();
			enterRoomRsp.deskCount = 0;
			enterRoomRsp.desksInfo = new Array();
			enterRoomRsp.errorNum = errorNum;
			enterRoomRsp.msgSeq = 30000003;
			enterRoomRsp.totalChipsOfPlayer = 0;
			_callbackFun(enterRoomRsp);
		}
		
		private function sendEnterRoomCmd():void
		{
			if (null == _enterRoomCmdReq)
				return;
			var roomsInfo:Array = _RoomsManager.getDirectoryRoomsInfo();
			if (null == roomsInfo || 0 >= roomsInfo.length)
				return ;
			if (0 > _enterRoomCmdReq.roomId || roomsInfo.length <= _enterRoomCmdReq.roomId)
				return ;
			var roomInfo:DirectoryRoomInfo = roomsInfo[_enterRoomCmdReq.roomId] as DirectoryRoomInfo;
			if (null == roomInfo)
				return;
			var cmd:EnterRoomCmdReq = new EnterRoomCmdReq();
			cmd.roomId = roomInfo.id;
			cmd.reserve = 0;
			if (0 != sendCmdToServer(cmd))
			{
				returnEnterRoomError( -4);
			}
		}
		
		private function recvEventCallback(eventType:int,socket:TCPSocket):void
		{
			switch(eventType)
			{
				case 0://接收数据回调
				recvDataCallback();
				break;
				case 1://建立连接
				connectedResult(0);
				break;
				case 2://连接被对方关闭
				//trace("连接被对方关闭");
				//Alert.show("服务器关闭连接");
				break;
				case 3://主动关闭。
				trace("主动关闭");
				break;
				case 4://未知出错。
				connectedResult(1);
				break;
				default:
				break;
			}
		}
		
		public function sendCmdToServer(cmd:abCommand):int
		{
			if (null == cmd)
				return -1;
			if(CommandType.CMD_TYPE_GETROOMSOFGAME_REQ == cmd.getCmdType())
			{
				_RoomsManager.getRoomInfoFromDirectoryServer();//开始连接，并获取房间信息。
				return 0;
			}
			else if(CommandType.CMD_TYPE_ENTERROOM_REQ == cmd.getCmdType())
			{
				//登录房间。
				_enterRoomCmdReq = cmd as EnterRoomCmdReq;//此时房间的ID是索引信息。
				if (null == _enterRoomCmdReq)
					return -2;
				var roomsInfo:Array = _RoomsManager.getDirectoryRoomsInfo();
				if (null == roomsInfo || 0 >= roomsInfo.length)
					return -3;
				if (0 > _enterRoomCmdReq.roomId || roomsInfo.length <= _enterRoomCmdReq.roomId)
					return -4;
				var roomInfo:DirectoryRoomInfo = roomsInfo[_enterRoomCmdReq.roomId] as DirectoryRoomInfo;
				if (null == roomInfo)
					return -5;
				if (0 != connectToServer(roomInfo.gateIp, roomInfo.gatePort))
					return -6;
				return 0;
			}
			
			var bytes:ByteArray = new ByteArray();
			var len:int = 0;
			len = _protocolTranslater.convertToBytes(cmd, bytes, 4);
			if (0 >= len)
				return -1;
			bytes.position = 0;
			//bytes.writeInt(len);
			bytes[0] = (len & 0xff);
			bytes[1] = ((len >> 8) & 0xff);
			bytes[2] = ((len >> 16) & 0xff);
			bytes[3] = ((len >> 24) & 0xff);			
			bytes.position = len;
			var lentemp:int = 0;
			var ret:int = -1;
			while (lentemp < len)
			{				
				bytes.position = lentemp;
				ret = _tcpSocket.send(bytes, lentemp, len - lentemp);
				if (0 > ret)
				{
					trace("sendCmdToServer send data error!ret = " + ret);
					return -2;
				}
				lentemp += ret;
			}
			return 0;
		}
		
		public function close():void
		{
			if (null != _tcpSocket)
			{
				_tcpSocket.close();
				_tcpSocket = null;
			}
		}
	}
	
}